package org.example.controller;

import org.example.entity.GameRecord;
import org.example.mapper.GameRecordMapper;
import org.example.service.GameRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.json.JSONArray;
import org.json.JSONException;

@RestController
@RequestMapping("/api/wuziqi")
public class WuziqiApiController {

    private static final int BOARD_SIZE = 19;
    private static final int INITIAL_DEPTH = 3;
    private int[][] gameBoard = new int[BOARD_SIZE][BOARD_SIZE];
    private int currentPlayer = 1;

    @Autowired
    private GameRecordService gameRecordService; // 确保这行存在
    private Object gameRecordMapper;

    public WuziqiApiController(GameRecordService gameRecordService) {
        this.gameRecordService = gameRecordService;
    }

    // 示例：获取所有游戏记录
    @GetMapping("/game-records")
    public ResponseEntity<List<GameRecord>> getAllGameRecords() {
        GameRecordMapper gameRecordMapper = null;
        List<GameRecord> gameRecords = gameRecordMapper.getAllGameRecords();
        return ResponseEntity.ok(gameRecords);
    }


    @PostMapping("/move")
    public ResponseEntity<MoveResponse> move(@RequestBody MoveRequest request) {
        int row = request.getRow();
        int col = request.getCol();

        if (gameBoard[row][col] == 0) {
            gameBoard[row][col] = currentPlayer;
            boolean win = checkWin(row, col, currentPlayer);
            boolean draw = isBoardFull();
            MoveResponse response = new MoveResponse(win, draw);
            currentPlayer = currentPlayer == 1 ? 2 : 1;
            return ResponseEntity.ok(response);
        } else {
            return ResponseEntity.badRequest().body(null);
        }
    }

    @PostMapping("/new-game")
    public ResponseEntity<Void> newGame() {
        gameBoard = new int[BOARD_SIZE][BOARD_SIZE];
        currentPlayer = 1;
        return ResponseEntity.ok().build();
    }

    @GetMapping("/ai-move")
    public ResponseEntity<AIMoveResponse> aiMove() {
        int depth = adjustDepth();
        int[] move = findBestMove(depth);
        int row = move[0];
        int col = move[1];

        if (gameBoard[row][col] == 0) {
            gameBoard[row][col] = currentPlayer;
            boolean win = checkWin(row, col, currentPlayer);
            boolean draw = isBoardFull();
            AIMoveResponse response = new AIMoveResponse(row, col, win, draw);
            currentPlayer = currentPlayer == 1 ? 2 : 1;
            return ResponseEntity.ok(response);
        } else {
            return ResponseEntity.badRequest().body(null);
        }
    }

    // 保存游戏记录
    @PostMapping("/save-game")
    public ResponseEntity<String> saveGame(@RequestBody SaveGameRequest request) {
        String username = request.getUsername();
        List<GameRecord> existingRecords = gameRecordService.lambdaQuery()
                .eq(GameRecord::getUsername, username)
                .list();

        if (!existingRecords.isEmpty()) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body("该用户已存在存档");
        }

        String boardData = request.getBoardData();
        GameRecord gameRecord = new GameRecord();
        gameRecord.setUsername(username);
        gameRecord.setBoardData(boardData);
        gameRecord.setCurrentPlayer(currentPlayer);

        gameRecordService.save(gameRecord);
        return ResponseEntity.ok("存档成功");
    }

    // 加载游戏记录
    @GetMapping("/load-game")
    public ResponseEntity<LoadGameResponse> loadGame(@RequestParam String username) {
        GameRecord gameRecord = gameRecordService.findTopByUsernameOrderByIdDesc(username);
        if (gameRecord != null) {
            String boardData = gameRecord.getBoardData();
            if (boardData == null) {
                return ResponseEntity.badRequest().body(null);
            }
            int currentPlayer = gameRecord.getCurrentPlayer();
            loadBoardData(boardData);
            this.currentPlayer = currentPlayer;
            LoadGameResponse response = new LoadGameResponse(boardData, currentPlayer);
            return ResponseEntity.ok(response);
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    private void loadBoardData(String boardData) {
        try {
            JSONArray rows = new JSONArray(boardData);
            for (int i = 0; i < BOARD_SIZE; i++) {
                JSONArray cells = rows.getJSONArray(i);
                for (int j = 0; j < BOARD_SIZE; j++) {
                    gameBoard[i][j] = cells.getInt(j);
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    private int[] findBestMove(int depth) {
        int bestScore = Integer.MIN_VALUE;
        int bestRow = 0;
        int bestCol = 0;
        int alpha = Integer.MIN_VALUE;
        int beta = Integer.MAX_VALUE;

        for (Move move : getEmptyCells()) {
            int row = move.row;
            int col = move.col;
            gameBoard[row][col] = currentPlayer;
            int score = minimax(depth - 1, false, alpha, beta);
            gameBoard[row][col] = 0;

            if (score > bestScore) {
                bestScore = score;
                bestRow = row;
                bestCol = col;
            }
            alpha = Math.max(alpha, bestScore);
        }

        return new int[]{bestRow, bestCol};
    }

    private int minimax(int depth, boolean isMaximizing, int alpha, int beta) {
        Integer winner = checkWinner();
        List<Move> emptyCells = getEmptyCells();

        if (depth == 0 || emptyCells.isEmpty() || winner != null) {
            return evaluateBoard(winner);
        }

        if (isMaximizing) {
            int bestScore = Integer.MIN_VALUE;
            for (Move move : emptyCells) {
                int row = move.row;
                int col = move.col;
                gameBoard[row][col] = currentPlayer;
                int score = minimax(depth - 1, false, alpha, beta);
                gameBoard[row][col] = 0;
                bestScore = Math.max(bestScore, score);
                alpha = Math.max(alpha, bestScore);
                if (beta <= alpha) {
                    break;
                }
            }
            return bestScore;
        } else {
            int bestScore = Integer.MAX_VALUE;
            int opponent = currentPlayer == 1 ? 2 : 1;
            for (Move move : emptyCells) {
                int row = move.row;
                int col = move.col;
                gameBoard[row][col] = opponent;
                int score = minimax(depth - 1, true, alpha, beta);
                gameBoard[row][col] = 0;
                bestScore = Math.min(bestScore, score);
                beta = Math.min(beta, bestScore);
                if (beta <= alpha) {
                    break;
                }
            }
            return bestScore;
        }
    }

    private Integer checkWinner() {
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (gameBoard[i][j] != 0) {
                    if (checkWin(i, j, gameBoard[i][j])) {
                        return gameBoard[i][j];
                    }
                }
            }
        }
        return null;
    }

    private int evaluateBoard(Integer winner) {
        if (winner != null) {
            return winner == currentPlayer ? 100000 : -100000;
        }
        if (isBoardFull()) {
            return 0;
        }

        int score = 0;
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (gameBoard[i][j] == 0) {
                    score += evaluatePosition(i, j, currentPlayer) - evaluatePosition(i, j, currentPlayer == 1 ? 2 : 1);
                }
            }
        }
        return score;
    }

    private int evaluatePosition(int row, int col, int player) {
        int score = 0;
        // 水平方向
        score += evaluateDirection(row, col, player, 1, 0);
        // 垂直方向
        score += evaluateDirection(row, col, player, 0, 1);
        // 主对角线方向
        score += evaluateDirection(row, col, player, 1, 1);
        // 副对角线方向
        score += evaluateDirection(row, col, player, 1, -1);
        return score;
    }

    private int evaluateDirection(int row, int col, int player, int dRow, int dCol) {
        int count = 0;
        int blockByOpponent = 0;
        int openEnds = 0;

        for (int i = 1; i < 5; i++) {
            int r = row + i * dRow;
            int c = col + i * dCol;
            if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE) {
                break;
            }
            if (gameBoard[r][c] == player) {
                count++;
            } else if (gameBoard[r][c] == (player == 1 ? 2 : 1)) {
                blockByOpponent++;
                break;
            } else {
                openEnds++;
                break;
            }
        }

        for (int i = 1; i < 5; i++) {
            int r = row - i * dRow;
            int c = col - i * dCol;
            if (r < 0 || r >= BOARD_SIZE || c < 0 || c >= BOARD_SIZE) {
                break;
            }
            if (gameBoard[r][c] == player) {
                count++;
            } else if (gameBoard[r][c] == (player == 1 ? 2 : 1)) {
                blockByOpponent++;
                break;
            } else {
                openEnds++;
                break;
            }
        }

        if (count == 4 && blockByOpponent == 0) {
            return 10000;
        }
        if (count == 3 && blockByOpponent == 0 && openEnds == 2) {
            return 5000;
        }
        if (count == 3 && blockByOpponent == 0) {
            return 1000;
        }
        if (count == 2 && blockByOpponent == 0 && openEnds == 2) {
            return 500;
        }
        if (count == 2 && blockByOpponent == 0) {
            return 100;
        }
        if (count == 1 && blockByOpponent == 0 && openEnds == 2) {
            return 50;
        }
        if (count == 1 && blockByOpponent == 0) {
            return 10;
        }
        return 0;
    }

    private List<Move> getEmptyCells() {
        List<Move> emptyCells = new ArrayList<>();
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (gameBoard[i][j] == 0) {
                    emptyCells.add(new Move(i, j));
                }
            }
        }
        return emptyCells;
    }

    private boolean checkWin(int row, int col, int player) {
        return checkLine(row, col, player, 1, 0) ||
                checkLine(row, col, player, 0, 1) ||
                checkLine(row, col, player, 1, 1) ||
                checkLine(row, col, player, 1, -1);
    }

    private boolean checkLine(int row, int col, int player, int dRow, int dCol) {
        int count = 1;
        for (int i = 1; i < 5; i++) {
            if (getCellValue(row + i * dRow, col + i * dCol) != player) {
                break;
            }
            count++;
        }
        for (int i = 1; i < 5; i++) {
            if (getCellValue(row - i * dRow, col - i * dCol) != player) {
                break;
            }
            count++;
        }
        return count >= 5;
    }

    private int getCellValue(int row, int col) {
        if (row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE) {
            return 0;
        }
        return gameBoard[row][col];
    }

    private boolean isBoardFull() {
        for (int[] row : gameBoard) {
            for (int cell : row) {
                if (cell == 0) {
                    return false;
                }
            }
        }
        return true;
    }

    private int adjustDepth() {
        int emptyCount = 0;
        for (int[] row : gameBoard) {
            for (int cell : row) {
                if (cell == 0) {
                    emptyCount++;
                }
            }
        }
        if (emptyCount > 150) {
            return INITIAL_DEPTH - 1;
        }
        if (emptyCount < 50) {
            return INITIAL_DEPTH + 1;
        }
        return INITIAL_DEPTH;
    }

    static class MoveRequest {
        private int row;
        private int col;

        public int getRow() {
            return row;
        }

        public void setRow(int row) {
            this.row = row;
        }

        public int getCol() {
            return col;
        }

        public void setCol(int col) {
            this.col = col;
        }
    }

    static class MoveResponse {
        private boolean win;
        private boolean draw;

        public MoveResponse(boolean win, boolean draw) {
            this.win = win;
            this.draw = draw;
        }

        public boolean isWin() {
            return win;
        }

        public void setWin(boolean win) {
            this.win = win;
        }

        public boolean isDraw() {
            return draw;
        }

        public void setDraw(boolean draw) {
            this.draw = draw;
        }
    }

    static class AIMoveResponse {
        private int row;
        private int col;
        private boolean win;
        private boolean draw;

        public AIMoveResponse(int row, int col, boolean win, boolean draw) {
            this.row = row;
            this.col = col;
            this.win = win;
            this.draw = draw;
        }

        public int getRow() {
            return row;
        }

        public void setRow(int row) {
            this.row = row;
        }

        public int getCol() {
            return col;
        }

        public void setCol(int col) {
            this.col = col;
        }

        public boolean isWin() {
            return win;
        }

        public void setWin(boolean win) {
            this.win = win;
        }

        public boolean isDraw() {
            return draw;
        }

        public void setDraw(boolean draw) {
            this.draw = draw;
        }
    }

    static class LoadGameResponse {
        private String boardData;
        private int currentPlayer;

        public LoadGameResponse(String boardData, int currentPlayer) {
            this.boardData = boardData;
            this.currentPlayer = currentPlayer;
        }

        public String getBoardData() {
            return boardData;
        }

        public void setBoardData(String boardData) {
            this.boardData = boardData;
        }

        public int getCurrentPlayer() {
            return currentPlayer;
        }

        public void setCurrentPlayer(int currentPlayer) {
            this.currentPlayer = currentPlayer;
        }
    }

    static class SaveGameRequest {
        private String username;
        private String boardData;

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getBoardData() {
            return boardData;
        }

        public void setBoardData(String boardData) {
            this.boardData = boardData;
        }
    }

    static class Move {
        int row;
        int col;

        Move(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }
}